package com.bocloud.cmp.driver.providers.vmware;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bocloud.cmp.driver.providers.NetworkDriver;
import com.bocloud.cmp.model.NetworkModel;
import com.bocloud.cmp.model.SubnetModel;
import com.bocloud.cmp.model.SwitchModel;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.utils.ListTool;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.vmware.vim25.DVPortgroupConfigSpec;
import com.vmware.vim25.DVSConfigSpec;
import com.vmware.vim25.DVSCreateSpec;
import com.vmware.vim25.DistributedVirtualSwitchHostMemberConfigSpec;
import com.vmware.vim25.DistributedVirtualSwitchHostMemberPnicBacking;
import com.vmware.vim25.DistributedVirtualSwitchHostMemberPnicSpec;
import com.vmware.vim25.HostIpRouteConfig;
import com.vmware.vim25.HostNetworkInfo;
import com.vmware.vim25.HostNetworkPolicy;
import com.vmware.vim25.HostPortGroup;
import com.vmware.vim25.HostPortGroupConfig;
import com.vmware.vim25.HostPortGroupSpec;
import com.vmware.vim25.HostSystemConnectionState;
import com.vmware.vim25.HostVirtualNic;
import com.vmware.vim25.HostVirtualSwitch;
import com.vmware.vim25.HostVirtualSwitchBondBridge;
import com.vmware.vim25.HostVirtualSwitchConfig;
import com.vmware.vim25.HostVirtualSwitchSpec;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.PhysicalNic;
import com.vmware.vim25.mo.Datacenter;
import com.vmware.vim25.mo.DistributedVirtualPortgroup;
import com.vmware.vim25.mo.DistributedVirtualSwitch;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.Network;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VmwareDistributedVirtualSwitch;

/**
 * vmware网络操作接口实现类
 * 
 * @author weiwei
 *
 */
public class VmwareNetworkDriver extends VmwareDriver implements NetworkDriver {

	private static Logger logger = LoggerFactory.getLogger(VmwareNetworkDriver.class);

	/**
	 * 
	 */
	public VmwareNetworkDriver() {
		super();
	}

	/**
	 * @param endpoint
	 * @param username
	 * @param password
	 */
	public VmwareNetworkDriver(String endpoint, String username, String password) {
		super(endpoint, username, password);
	}

	@Override
	public BsmResult list() {
		try {
			ManagedEntity[] hostSystemArray = new InventoryNavigator(this.getRootFolder())
					.searchManagedEntities("HostSystem");
			List<NetworkModel> networkModels = new ArrayList<>();
			List<SubnetModel> subnetModels = new ArrayList<>();
			SubnetModel switchSubnetModel = new SubnetModel();
			for (ManagedEntity hostSystemManagedEntity : hostSystemArray) {
				HostSystem hostSystem = (HostSystem) hostSystemManagedEntity;
				if (hostSystem == null) {
					logger.error("No VM template found");
					return new BsmResult(false, "创建虚拟机失败：模板不存在！");
				}
				SubnetModel nicSubnetModel = new SubnetModel();
				HostNetworkInfo nwi = hostSystem.getConfig().getNetwork();
				HostIpRouteConfig hostIpRouteConfig = nwi.getIpRouteConfig();
				if (hostIpRouteConfig != null) {
					switchSubnetModel.setGateway(hostIpRouteConfig.getDefaultGateway());
					nicSubnetModel.setGateway(hostIpRouteConfig.getDefaultGateway());
				}

				HostPortGroup[] portgroups = nwi.getPortgroup();
				Map<String, String> pgMap = new HashMap<String, String>();
				for (HostPortGroup portgroup : portgroups) {
					pgMap.put(portgroup.getKey(), portgroup.getSpec().getName());
				}
				PhysicalNic[] pnics = nwi.getPnic();
				Map<String, String> pnicMap = new HashMap<String, String>();
				for (PhysicalNic pnic : pnics) {
					pnicMap.put(pnic.getKey(), pnic.getMac());
				}

				HostVirtualSwitch[] vswtichs = nwi.getVswitch();
				for (HostVirtualSwitch vswitch : vswtichs) {
					NetworkModel switchModel = new NetworkModel();
					switchModel.setType("VirtualSwitch");
					switchModel.setName(vswitch.getName());
					String[] macKeys = vswitch.getPnic();
					String macValue = "";
					if (macKeys != null) {
						for (String key : macKeys) {
							macValue = pnicMap.get(key) + ";" + macValue;
						}
						switchSubnetModel.setMac(macValue);
					}
					String[] pgs = vswitch.getPortgroup();
					String pgValue = "";
					if (pgs != null) {
						for (String pg : pgs) {
							pgValue = (pgMap.get(pg)) + ";" + pgValue;
						}
						switchSubnetModel.setPortgroup(pgValue);
					}
					subnetModels.add(switchSubnetModel);
					switchModel.setSubnets(subnetModels);
					subnetModels.add(switchSubnetModel);
				}

				HostVirtualNic[] virtualnics = nwi.getVnic();
				for (HostVirtualNic virtualnic : virtualnics) {
					NetworkModel nicModel = new NetworkModel();
					nicModel.setType("VirtualNic");
					nicModel.setName(virtualnic.getDevice());
					nicSubnetModel.setPortgroup(virtualnic.getPortgroup());
					nicSubnetModel.setMac(virtualnic.getSpec().getMac());
					nicSubnetModel.setAddress(virtualnic.getSpec().getIp().getIpAddress());
					nicSubnetModel.setHostRoutes(virtualnic.getSpec().getIp().getSubnetMask());
					if (virtualnic.getSpec().getIp().getIpV6Config().getDhcpV6Enabled()) {
						nicSubnetModel.setIpVersion("IPv6");
					} else {
						nicSubnetModel.setIpVersion("IPv4");
					}
					networkModels.add(nicModel);
				}
			}
			return new BsmResult(true, networkModels, "获取网络信息成功!");
		} catch (Exception e) {
			logger.error("get network failure:", e);
			return new BsmResult(false, "获取网络信息失败!");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}

	}

	@Override
	public BsmResult remove(String String) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult detail(String networkId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult create(NetworkModel model) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult modify(NetworkModel model) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult createDSwitch(SwitchModel switchModel) {
		try {
			ManagedEntity managedEntity = new InventoryNavigator(this.getRootFolder()).searchManagedEntity("Datacenter",
					switchModel.getVdcName());
			if (null != managedEntity) {
				Datacenter datacenter = (Datacenter) managedEntity;
				// 创建分布式交换机使用folder且必须是networkFolder
				Folder folder = datacenter.getNetworkFolder();
				// 获取已经存在的网络名称
				ManagedEntity[] managedEntities = folder.getChildEntity();
				if (null != managedEntities) {
					for (ManagedEntity entity : managedEntities) {
						if (switchModel.getName().equals(entity.getName())) {
							return new BsmResult(false, "创建失败：名称不能重复");
						}
					}
				}
				// 获取所有的物理机器以及物理网卡信息
				Map<String, List<String>> hostMap = switchModel.getValues();
				// 存放物理机的名称及key值
				Map<String, String> hostKeyMap = Maps.newHashMap();
				// 获取hostName对应的物理机的key值
				for (String hostName : hostMap.keySet()) {
					ManagedEntity entity = new InventoryNavigator(this.getRootFolder())
							.searchManagedEntity("HostSystem", hostName);
					if (null != entity) {
						HostSystem hostSystem = (HostSystem) entity;
						hostKeyMap.put(hostName, hostSystem.getMOR().getVal());
					} else {
						return new BsmResult(false, "创建分布式交换机失败：获取物理主机value值失败");
					}
				}
				// 物理机数组
				DistributedVirtualSwitchHostMemberConfigSpec[] dvshmcsArray = new DistributedVirtualSwitchHostMemberConfigSpec[hostMap
						.size()];
				int dvshmcsIndex = 0;
				for (String hostName : hostMap.keySet()) {
					List<String> pNics = hostMap.get(hostName);
					// hostName主机对应的物理网卡
					if (!ListTool.isEmpty(pNics)) {
						DistributedVirtualSwitchHostMemberPnicSpec[] pnicSpecs = new DistributedVirtualSwitchHostMemberPnicSpec[pNics
								.size()];
						int specIndex = 0;
						for (String pNic : pNics) {
							DistributedVirtualSwitchHostMemberPnicSpec pnicSpc = new DistributedVirtualSwitchHostMemberPnicSpec();
							pnicSpc.setPnicDevice(pNic);
							pnicSpecs[specIndex++] = pnicSpc;
						}

						// 某一个物理机所包含的物理网卡的信息
						DistributedVirtualSwitchHostMemberPnicBacking dvshmpb = new DistributedVirtualSwitchHostMemberPnicBacking();
						dvshmpb.setPnicSpec(pnicSpecs);
						// 要创建的分布式交换机所需的物理机相关配置
						DistributedVirtualSwitchHostMemberConfigSpec dvshmcs = new DistributedVirtualSwitchHostMemberConfigSpec();
						// 设置物理网卡
						dvshmcs.setBacking(dvshmpb);
						// 某一台特定物理机
						ManagedObjectReference reference = new ManagedObjectReference();
						reference.setType("HostSystem");// 类型
						reference.setVal(hostKeyMap.get(hostName));// 物理机的唯一value值
						HostSystem hostSystem = new HostSystem(this.getRootFolder().getServerConnection(), reference);
						// 设置物理机
						dvshmcs.setHost(hostSystem.getMOR());
						dvshmcs.setOperation("add");

						dvshmcsArray[dvshmcsIndex++] = dvshmcs;
					}
				}
				// 设置物理机
				DVSConfigSpec dvsConfigSpec = new DVSConfigSpec();
				dvsConfigSpec.setHost(dvshmcsArray);
				dvsConfigSpec.setName(switchModel.getName());
				// 分布式虚拟机配置
				DVSCreateSpec dvs = new DVSCreateSpec();
				dvs.setConfigSpec(dvsConfigSpec);
				// 创建分布式虚拟机任务
				Task dvsTask = folder.createDVS_Task(dvs);
				if (dvsTask.waitForTask().equals(Task.SUCCESS)) {
					// 初始化所创建的分布式虚拟机
					DistributedVirtualSwitch dvSwitch = new DistributedVirtualSwitch(folder.getServerConnection(),
							(ManagedObjectReference) dvsTask.getTaskInfo().getResult());
					// 分布式端口组配置
					DVPortgroupConfigSpec dvP = new DVPortgroupConfigSpec();
					dvP.setType("earlyBinding");// 分布式端口组的类型
					dvP.setName(switchModel.getName() + "PortGroup");// 分布式端口组的名称
					dvP.setNumPorts(switchModel.getPortGroupNum());// 分布式端口组端口数量
					// 分布式端口组创建任务
					Task groupTask = dvSwitch.createDVPortgroup_Task(dvP);
					if (groupTask.waitForTask().equals(Task.SUCCESS)) {
						ManagedEntity vdcEntity = new InventoryNavigator(this.getRootFolder())
								.searchManagedEntity("Datacenter", switchModel.getVdcName());
						Datacenter center = (Datacenter) vdcEntity;
						ManagedEntity[] entities = center.getNetworkFolder().getChildEntity();
						List<NetworkModel> networks = Lists.newArrayList();
						for (ManagedEntity network : entities) {
							if (network instanceof VmwareDistributedVirtualSwitch) {
								NetworkModel networkModel = new NetworkModel(network.getName(), "", "DVSWITCH",
										network.getOverallStatus().toString(), null, null, new ArrayList<>(), "",
										network.getMOR().getVal(),
										((VmwareDistributedVirtualSwitch) network).getConfig().getNumPorts());
								networks.add(networkModel);
							}
						}
						return new BsmResult(true, networks, "创建分布式交换机成功");
					}
				} else {
					return new BsmResult(false, "创建分布式交换机失败");
				}
			}
		} catch (Exception e) {
			logger.error("", e);
			return new BsmResult(false, "创建分布式交换机失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
		return new BsmResult(false, "创建分布式虚拟机失败");
	}

	@Override
	public BsmResult createVSwitch(SwitchModel switchModel) {
		try {
			// 获取所有的物理机器以及物理网卡信息(此时该map中只有一条记录，即一台物理机)
			Map<String, List<String>> hostMap = switchModel.getValues();
			for (String hostName : hostMap.keySet()) {
				ManagedEntity entity = new InventoryNavigator(this.getRootFolder()).searchManagedEntity("HostSystem",
						hostName);
				HostSystem host = (HostSystem) entity;
				// 获取主机当前连接状态
				HostSystemConnectionState connState = host.getSummary().getRuntime().getConnectionState();
				if (connState.equals(HostSystemConnectionState.disconnected)) {
					return new BsmResult(false, "主机处于断开状态，无法创建网络");
				}
				// 如果该机器上已存在相应的标准交换机名称和虚拟机端口组名称，标准交换机创建不成功
				// 获取该物理机上的所有虚拟机端口组
				Network[] networks = host.getNetworks();
				// 获取机器上的标准交换机
				HostVirtualSwitchConfig[] vSwitchs = host.getHostNetworkSystem().getNetworkConfig().getVswitch();
				// 判断该机器上是否已存在该端口组名称
				for (Network portGroup : networks) {
					if (portGroup.getName().equals(switchModel.getPortGroupName())) {
						return new BsmResult(false, "创建失败：该机器上已存在该端口组名称!");
					}
				}
				// 判断该机器上是否已存在该交换机名称
				for (HostVirtualSwitchConfig vSwitch : vSwitchs) {
					if (vSwitch.getName().equals(switchModel.getName())) {
						return new BsmResult(false, "创建失败:该机器上已存在该交换机名称！");
					}
				}

				List<String> pNicNames = hostMap.get(hostName);// 该物理机对应的物理网卡

				HostVirtualSwitchSpec vSwitchSpec = new HostVirtualSwitchSpec();
				if (pNicNames.size() != 0) {
					// 使用BondBridge方式创建
					HostVirtualSwitchBondBridge bondBridge = new HostVirtualSwitchBondBridge();
					// 设置该物理机下物理网卡的名称
					bondBridge.setNicDevice(pNicNames.toArray(new String[pNicNames.size()]));
					vSwitchSpec.setBridge(bondBridge);
				}

				// 设置端口数量
				vSwitchSpec.setNumPorts(switchModel.getPortGroupNum() + 8);
				// 物理机上创建标准交换机
				host.getHostNetworkSystem().addVirtualSwitch(switchModel.getName(), vSwitchSpec);
				// 添加虚拟机端口组
				HostPortGroupSpec portGroupSpec = new HostPortGroupSpec();
				portGroupSpec.setVswitchName(switchModel.getName());
				portGroupSpec.setName(switchModel.getPortGroupName());
				portGroupSpec.setVlanId(0);
				portGroupSpec.setPolicy(new HostNetworkPolicy());

				host.getHostNetworkSystem().addPortGroup(portGroupSpec);

			}

			ManagedEntity vdcEntity = new InventoryNavigator(this.getRootFolder()).searchManagedEntity("Datacenter",
					switchModel.getVdcName());
			Datacenter center = (Datacenter) vdcEntity;
			List<NetworkModel> networks = Lists.newArrayList();
			ManagedEntity[] entities = center.getNetworkFolder().getChildEntity();
			for (ManagedEntity network : entities) {
				if (network instanceof Network && !(network instanceof DistributedVirtualPortgroup)) {
					int portNum = -1;
					HostSystem[] hosts = ((Network) network).getHosts();
					if (hosts.length > 0) {
						HostSystem host = ((Network) network).getHosts()[0];
						HostPortGroupConfig[] portGroupConfigs = host.getHostNetworkSystem().getNetworkConfig()
								.getPortgroup();
						HostVirtualSwitchConfig[] vSwitchConfigs = host.getHostNetworkSystem().getNetworkConfig()
								.getVswitch();
						for (HostPortGroupConfig portGroupConfig : portGroupConfigs) {
							if (network.getName().equals(portGroupConfig.getSpec().getName())) {
								for (HostVirtualSwitchConfig vSwitchConfig : vSwitchConfigs) {
									if (portGroupConfig.getSpec().getVswitchName().equals(vSwitchConfig.getName())) {
										portNum = vSwitchConfig.getSpec().getNumPorts();
										break;
									}
								}
							}
						}
					}
					if (portNum != -1 && portNum >= 8) {
						NetworkModel networkModel = new NetworkModel(network.getName(), "", "VSWITCH",
								network.getOverallStatus().toString(), null, null, new ArrayList<>(), "",
								network.getMOR().getVal(), portNum - 8);
						networks.add(networkModel);
					} else {
						NetworkModel networkModel = new NetworkModel(network.getName(), "", "VSWITCH",
								network.getOverallStatus().toString(), null, null, new ArrayList<>(), "",
								network.getMOR().getVal(), null);
						networks.add(networkModel);
					}
				}
			}
			return new BsmResult(true, networks, "创建标准交换机成功");
		} catch (RemoteException e) {
			logger.error("创建标准交换机异常", e);
			return new BsmResult(false, "创建标准交换机失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

}
